/*!\file  boot_init.c The first C code after bootstrap.
 *
 *      This file is part of the micro-rtos package.
 *
 *  Copyright (c) 2008-2009 by Gabriel Zabusek <gabriel.zabusek@gmail.com>
 *
 *      This program is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU General Public License
 *      as published by the Free Software Foundation; either version
 *      2 of the License, or (at your option) any later version.
 */


/*
 * Boot initialization procedures
 *
 * Implements second stage basic hw initializations (PLL,MAM,..) and 
 * sets up the timers
 *
 * Author: Gabriel Zabusek, gabriel.zabusek@gmail.com
 * 	  - under trademark of GZembedded software 2008
 * */

#include <boot/lpc2103.h>
#include <kernel/critical.h>
#include <kernel/interrupt.h>
#include <kernel/task.h>
#include <kernel/main.h>
#include <include/types.h>

#define LED1 (1<<17)
#define LED2 (1<<18)
#define LEDS (LED1 | LED2)

#define NOP	asm volatile ("nop")

/*************************************************************************
*
*************************************************************************/


//functions declared in this file:
void delay(void);
void pll_feed(void);
void init(void);
int boot_init(void);

/*************************************************************************
*
*************************************************************************/

void pll_feed(void)
{
        PLLFEED = 0xAA;
        PLLFEED = 0x55;
}


void init(void)
{
	/*
	 * set power control. switch off all peripherals but timer0
	 */
	
	//PCONP = 0x00000002; // not used as we dont know which peripherals should be in off state

	MEMMAP = 0x01; //user flash mode - code runs from flash, no remmaping

	// crystal - 19.6608 MHz
        // desired freq: 3*crystal = 58.9824
        //  => M = 3
        //
        // P = Fcco / (CCLK * 2) = Fcco / ( 117.9648 )
        //  where Fcco must be between 156MHz and 320MHz
        //  => P = 2, Fcco = 235.9296MHz
        //  => PLLCFG = 0x22                                                 
        //  NOTE: for better understanding of this calculation read LPC2101/2/3 user manual            

	PLLCFG = 0x24;
        pll_feed();

        PLLCON = 0x1;
        pll_feed();

        while(!(PLLSTAT & PLLSTAT_PLOCK)){}

        PLLCON = 0x3;
        pll_feed();

        MAMTIM = 0x3; //3 cycles for fetch
        MAMCR  = 0x2; //enable

        APBDIV = 0x1; //peripheral bus clock same as proc clock -> PCLK = CCLK


	PINSEL0 = 0x00000000;	
	PINSEL1 = 0x00000000;

	//Set up the timer0 and its behaviour
	
	T0TCR = 0x2;		/*reset*/
	T0PR  = 0x00000000;	/*prescale*/
	T0MR0 = 0x00400000;
	//T0MR1 = 0x01000000;
	T0MR1 = 0xEA60 * 1000; //should be 1s exactly
	T0MCR = 031;		/*int and reset on MR1 match*/
	T0TCR = 0x1;		/*enable*/

	/*
	 * configure VIC (Vector Interrupt Controller)
	 */
	VIC_INT_ENABLE = 0x00000010;	/*timer0 enabled*/
	VIC_VECT_ADDR = (uint32_t)irq_h;

	//enter user mode, with enabled irq
//	EnterUserMode_IRQE();
}

/*************************************************************************
*dummy delay routine
*************************************************************************/
void delay(void)
{
	unsigned long	j;
	int i;
	for(j = 0; j != 0x10000; j++)
	    for(i=0;i<50;i++)
		NOP;
}

/*************************************************************************
* main program
*************************************************************************/



int boot_init(void)
{
	
	//Initialize the hardware
	init(); 
	//Initialize task structures
	init_task();
	main(0,0);
	

	return 0;
}
